/**
  ETFDAQ Project
  \class TAv1290A
  \brief 32 ch ECL input TDC VME module from CAEN Corp. of Italy
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2024-09-03
  \date 2024-09-03 last modified

  \copyright Copyright (c) 2024 IMP-CAS with LGPLv3 LICENSE
*/

#ifndef TAv1290A_h
#define TAv1290A_h

#include "TACAENCard.h"

class TAv1290A : public TACAENCard{
public:
  TAv1290A(TAController *ctrl, const TAYaml &c);
  virtual ~TAv1290A();

  virtual void Initialize() override;
  virtual void Identify() override; ///< read card info
  virtual void SlotInit() override; ///< write slot id and crate id
  /// \param level 1~7, 0 will disable the IRQ generation
  /// \param vector 0x00~0xFF, requested by vme ctrler to identify the interrupter
  /// \param nw: 16bits, trigger will be generated after nof buf words reaches nw
  virtual void ConfigIRQ(int level, int vector, int nw) const override;

  ///--- configuration ---///
  /// to select to write the header and EOB (End of Block)
  /// anyway when there are no accepted channels
  virtual void EnableEmpty() const override;
  virtual void EnableBerr() const override;
  /// so that ev len is written in event fifo
  virtual void EnableEventFIFO() const;
  /// 32 bits corresponds to ch 0-31 respectively. 1: enable; 0:disable
  void SetChOnPattern(uint32_t pattern);
  /// reset counter regs, the MEB, the trig counter, and the MEB ev counter
  virtual void SoftwareReset() override;

  ///--- the DAQ loop ---///
  virtual bool DataReady() const override; ///< true if buffered events are enough
  /// read all events in the buffer \retval nof words read
  virtual int ReadData(uint32_t *buf) override;
  /// read one event in the buffer \retval nof words read
  virtual int ReadEvent(uint32_t *buf) override;
  /// clear the module's multi-event buffers, the R/W pointers, and the event counters
  virtual void ClearData() override; // data reset (DR)
  virtual void ClearEventCounter() override; // clears the event counter
  virtual void ResetForNewRun() override;

  /// ---- print functions ---///
  /// \return the event counter register
  virtual void ReadEventCounter() override;
  virtual void Print() const override;
  virtual void PrintEvent(const uint32_t *ev)  override; ///< print one event

  // v1290a specific operations (mostly via opcode) //
  //-- trig configurations --//
  void SetTriggerMatchingMode() const;
  void SetMatchWindow(int width) const; ///< in ns
  void SetWindowOffset(int offset) const; ///< in ns
  void SetSearchMargin(int ex) const; ///< related to search window, in ns
  void SetRejectMargin(int rm) const; ///< related to reject latency, in ns
  void EnableTrigSubtraction(bool opt = true) const;
  void PrintTrigConfig() const; ///< read and print
  // miscellaneous
  void SetDetection(uint16_t mode) const; // 0:pair; 1:l; 2:t; 3: both
  void SetResolution(uint16_t mode) const; // 0: 800; 1: 200; 2:100; 3: 25
  /// 0: DRDY; 1: FULL; 2: ALM_FULL; 3: ERR
  void SetOutProg(uint16_t mode) const; ///< set the pout ECL output function

  static const int CLK = 25; ///< 1 clock cycle is 25ns
  static const int MAX_NEV = 0x7ff; ///< max nof buffered ev
  /// time for one channel of HPTDC VERY HIGH resolution mode: ~25ps
  static const double kBLIP[4];

protected:
  /// communications with the microcontroller //
  virtual bool ro() const; ///< read ok
  virtual bool wo() const; ///< write ok
  /// \param op: opcode: COMMAND(8bit)|OBJECT(8bit)
  virtual bool readop(uint16_t op, uint16_t *data, int nd = 1) const;
  virtual bool writeop(uint16_t op, const uint16_t *data, int nd = 1) const;
  virtual bool writeop(uint16_t op) const; ///< just write

  uint16_t fNw[MAX_NEV]; ///< nof words for the events in fifo
  int fMatchWindow, fWindowOffset, fRejectMargin, fSearchMargin;
  uint16_t fopd[128]; // just a temporary variable for readop and write op
  uint16_t fRes; ///< resolution
  double fBlip; ///< LSB in ps
};


struct v1290reg{
  static constexpr uint16_t Buffer =             0x0000; // ~0x0FFF, 4096B
  static constexpr uint16_t Control =            0x1000;
  static constexpr uint16_t Status =             0x100e;
  static constexpr uint16_t InterruptLevel =     0x100a;
  static constexpr uint16_t InterruptVector =    0x100c;
  static constexpr uint16_t GeoAddress =         0x100e;
  static constexpr uint16_t ModuleReset =        0x1014; // software reset
  static constexpr uint16_t SoftwareClear =      0x1016;
  static constexpr uint16_t SoftEventReset =     0x1018;
  static constexpr uint16_t SoftwareTrigger =    0x101a;
  static constexpr uint16_t EventCounter =       0x101c;
  static constexpr uint16_t EventStored =        0x1020;
  static constexpr uint16_t AlmostFullLevel =    0x1022; // evTrig but in words
  static constexpr uint16_t BLTEventNumber =     0x1024; // evTrig via BLT
  static constexpr uint16_t FirmwareRev =        0x1026;
  static constexpr uint16_t OutProg =            0x102c;
  static constexpr uint16_t Micro =              0x102e;
  static constexpr uint16_t MicroHandshake =     0x1030;
  static constexpr uint16_t SelectFlash =        0x1032;
  static constexpr uint16_t FlashMemory =        0x1034;
  static constexpr uint16_t EventFIFO =          0x1038;
  static constexpr uint16_t EventFIFOStored =    0x103c;
  static constexpr uint16_t EventFIFOStatus =    0x103e;
};

struct v1290mask{
  static constexpr uint16_t WRITE_OK =             0b01;
  static constexpr uint16_t READ_OK =              0b10;
  // the control register
  static constexpr uint16_t BERR_EN =               0x1;
  static constexpr uint16_t EMPTYEN =               0x8;
  static constexpr uint16_t COMPENSATIONEN =       0x20;
  static constexpr uint16_t EVENTFIFO =           0x100;
  // the status register
  static constexpr uint16_t DRDY =                  0x1;
  static constexpr uint16_t FIFODRDY =              0x1;
};

struct v1290rom{
  static constexpr uint16_t Version =            0x4030;
  static constexpr uint16_t Revision3 =          0x4040;
  static constexpr uint16_t Revision2 =          0x4044;
  static constexpr uint16_t Revision1 =          0x4048;
  static constexpr uint16_t Revision0 =          0x404c;
  static constexpr uint16_t SerialNo1 =          0x4080;
  static constexpr uint16_t SerialNo0 =          0x4084;
};

// opcode
struct v1290op{
  // acquisition mode
  static constexpr uint16_t TRIG_MATCH =         0x0000;
  static constexpr uint16_t CONT_STOR =          0x0100;
  // trigger
  static constexpr uint16_t SET_WIN_WIDTH =      0x1000;
  static constexpr uint16_t SET_WIN_OFFS =       0x1100;
  static constexpr uint16_t SET_SW_MARGIN =      0x1200;
  static constexpr uint16_t SET_REJ_MARGIN =     0x1300;
  static constexpr uint16_t EN_SUB_TRIG =        0x1400;
  static constexpr uint16_t DIS_SUB_TRIG =       0x1500;
  static constexpr uint16_t READ_TRIG_CONF =     0x1600;
  // tdc edge detection & resolution
  static constexpr uint16_t SET_DETECTION =      0x2200;
  static constexpr uint16_t SET_RESOLUTION =     0x2400;
  static constexpr uint16_t READ_RES =           0x2600;
  // tdc readout
  static constexpr uint16_t EN_HEAD_TRAILER =    0x3000;
  static constexpr uint16_t DIS_HEAD_TRAILER =   0x3100;
  static constexpr uint16_t READ_HEAD_TRAILER =  0x3200;
  static constexpr uint16_t READ_EVENT_SIZE =    0x3400;
  static constexpr uint16_t READ_FIFO_SIZE =     0x3c00;
  // channel enable
  static constexpr uint16_t EN_CHANNEL =         0x4000;
  static constexpr uint16_t DIS_CHANNEL =        0x4100;
  static constexpr uint16_t EN_ALL_CH =          0x4200;
  static constexpr uint16_t DIS_ALL_CH =         0x4300;
  static constexpr uint16_t WRITE_EN_PATTERN =   0x4400;
  static constexpr uint16_t READ_EN_PATTERN =    0x4500;
  static constexpr uint16_t WRITE_EN_PATTERN32 = 0x4600;
  static constexpr uint16_t READ_EN_PATTERN32 =  0x4700;
  // miscellaneous
  static constexpr uint16_t READ_MICRO_REV =     0x6100;
};

#endif
